package com.brillilab.service.core.user.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.brillilab.common.entity.PageVo;
import com.brillilab.common.utils.CodeUtil;
import com.brillilab.common.utils.DateUtil;
import com.brillilab.common.utils.MyBeanUtils;
import com.brillilab.config.InviteCodeProperties;
import com.brillilab.dao.mapper.user.InviteCodeMapper;
import com.brillilab.domain.enums.lab.InviteCodeTypeEnum;
import com.brillilab.domain.po.user.InviteCode;
import com.brillilab.domain.po.user.Users;
import com.brillilab.domain.vo.user.InviteCodeResult;
import com.brillilab.domain.vo.user.UserInfoVo;
import com.brillilab.service.core.user.IInviteCodeService;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 注册邀请码 服务实现类
 * </p>
 *
 * @author WuMenghao
 * @since 2019-09-30
 */
@Service
@Transactional
public class InviteCodeServiceImpl implements IInviteCodeService {

    @Resource
    private InviteCodeProperties properties;
    @Resource
    private InviteCodeMapper inviteCodeMapper;


    /**
     * 获取注册邀请码
     *
     * @param type     使用途径
     * @param num      生产数量
     * @param userInfo 实验室Id
     * @return
     */
    @Override
    public synchronized List<String> generateInviteCodes(String type, Integer num, UserInfoVo userInfo) {
        //生成code
        List<String> codes = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            codes.add(CodeUtil.getCode(properties.getSize(), properties.getSource()));
        }
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(new LambdaQueryWrapper<InviteCode>());
        codes = dealWithRepeat(inviteCodes, codes, num);

        Date expireDate = DateUtil.stringToDate(DateUtil.dateString(DateUtil.getEndDayOfMonth(), "yyyy-MM-dd HH:mm:ss"), "yyyy-MM-dd HH:mm:ss");
        //插入InviteCode记录
        List<InviteCode> inserts = codes.stream()
                .map(code -> new InviteCode(code, userInfo.getLabId(), type, userInfo.getName(), expireDate))
                .collect(Collectors.toList());
        inviteCodeMapper.insertBatch(inserts);
        return codes;
    }

    /**
     * 生成注册邀请码
     *
     * @param type
     * @param num
     * @param makeName
     * @return
     */
    @Override
    public synchronized List<String> generateInviteCode(String type, Integer num, String makeName) {
        //生成code
        List<String> codes = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            codes.add(CodeUtil.getCode(properties.getSize(), properties.getSource()));
        }
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(new LambdaQueryWrapper<InviteCode>());
        codes = dealWithRepeat(inviteCodes, codes, num);

        //后台生成邀请码，过期时间默认为30天
        Date expireDate = DateUtil.stringToDate(DateUtil.dateString(DateUtil.addDate(new Date(), 30), "yyyy-MM-dd HH:mm:ss"), "yyyy-MM-dd HH:mm:ss");
        //插入InviteCode记录
        List<InviteCode> inserts = codes.stream()
                .map(code -> new InviteCode(code, makeName, type, expireDate))
                .collect(Collectors.toList());
        inviteCodeMapper.insertBatch(inserts);
        return codes;
    }

    @Override
    public List<String> generateInviteCode(String type, Integer num, Users userInfo, Date expireDate) {
        //生成code
        List<String> codes = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            codes.add(CodeUtil.getCode(properties.getSize(), properties.getSource()));
        }
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(new LambdaQueryWrapper<InviteCode>());
        codes = dealWithRepeat(inviteCodes, codes, num);

        //插入InviteCode记录
        List<InviteCode> inserts = codes.stream()
                .map(code -> new InviteCode(code, userInfo.getLabId(), type, userInfo.getName(), expireDate))
                .collect(Collectors.toList());
        inviteCodeMapper.insertBatch(inserts);

        return codes;
    }

    @Override
    public List<String> generateInviteCode(String type, Integer num, Long labId, Users userInfo, Date expireDate) {
        //生成code
        List<String> codes = new ArrayList<>();
        for (int i = 0; i < num; i++) {
            codes.add(CodeUtil.getCode(properties.getSize(), properties.getSource()));
        }
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(new LambdaQueryWrapper<InviteCode>());
        codes = dealWithRepeat(inviteCodes, codes, num);

        //插入InviteCode记录
        List<InviteCode> inserts = codes.stream()
                .map(code -> new InviteCode(code, labId, type, userInfo.getName(), expireDate))
                .collect(Collectors.toList());
        inviteCodeMapper.insertBatch(inserts);

        return codes;
    }

    /**
     * 处理重复邀请码
     *
     * @param inviteCodes
     * @param codes
     * @return
     */
    private List<String> dealWithRepeat(List<InviteCode> inviteCodes, List<String> codes, Integer num) {
        codes = codes.stream().distinct().collect(Collectors.toList());
        List<String> all = inviteCodes.stream().map(InviteCode::getCode).collect(Collectors.toList());
        List<String> repeat = codes.stream().filter(all::contains).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(repeat) && codes.size() == num.longValue()) return codes;
        codes.removeAll(repeat);
        for (int i = 0; i < num - codes.size(); i++) {
            codes.add(CodeUtil.getCode(properties.getSize(), properties.getSource()));
        }
        return dealWithRepeat(inviteCodes, codes, num);
    }

    @Override
    public boolean updateById(InviteCode inviteCode) {
        int i = inviteCodeMapper.updateById(inviteCode);
        return i == 1;
    }

    @Override
    public synchronized boolean checkInviteCode(String code) {
        InviteCode inviteCode = inviteCodeMapper.selectOne(
                new LambdaQueryWrapper<InviteCode>()
                        .eq(InviteCode::getCode, code.toUpperCase()));

        return inviteCode != null && inviteCode.getState().equals(0) && inviteCode.getExpireDate().getTime() > new Date().getTime() ? true : false;
    }

    /**
     * 校验注邀请码
     *
     * @param code
     * @return
     */
    @Override
    public synchronized InviteCodeResult validateInviteCode(String code) {
        InviteCode inviteCode = inviteCodeMapper.selectOne(
                new LambdaQueryWrapper<InviteCode>()
                        .eq(InviteCode::getCode, code.toUpperCase()));
        if (inviteCode != null) {
            InviteCodeResult result = MyBeanUtils.copyBean(inviteCode, InviteCodeResult.class);
            if (inviteCode.getState() == 0) {
                result.setResult(true);
                inviteCode.setState(1);
                inviteCodeMapper.updateById(inviteCode);
            } else {
                result.setResult(false);
            }
            return result;
        }
        InviteCodeResult result = new InviteCodeResult();
        result.setResult(false);
        return result;
    }

    /**
     * 查询实验室PI分享邀请码
     *
     * @param labId
     * @param typeEnum
     * @return
     */
    @Override
    public InviteCode getLabShareInviteCode(Long labId, InviteCodeTypeEnum typeEnum) {
        return inviteCodeMapper.selectList(
                new LambdaQueryWrapper<InviteCode>()
                        .eq(InviteCode::getLabId, labId)
                        .like(InviteCode::getUseType, typeEnum.getName()))
                .stream().findFirst().orElse(null);
    }

    @Override
    public List<InviteCode> getInviteCodeInfo(Long labId) {
        LambdaQueryWrapper<InviteCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InviteCode::getLabId, labId);
        //生成时间大于等于月初1号
        wrapper.ge(InviteCode::getCreateTime, DateUtil.getBeginDayOfMonth());
        //过滤已过期的邀请码
        wrapper.gt(InviteCode::getExpireDate, new Date());
        return inviteCodeMapper.selectList(wrapper);
    }

    @Override
    public List<String> getUseTypeList() {
        LambdaQueryWrapper<InviteCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(InviteCode::getCreateTime);
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(queryWrapper);
        List<String> itemList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(inviteCodes)) {
            itemList = inviteCodes.stream().filter(p -> p.getUseType() != null).map(InviteCode::getUseType).distinct().collect(Collectors.toList());
        }
        return itemList;
    }

    @Override
    public List<String> getMakeNameList() {
        LambdaQueryWrapper<InviteCode> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(InviteCode::getCreateTime);
        List<InviteCode> inviteCodes = inviteCodeMapper.selectList(queryWrapper);
        List<String> itemList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(inviteCodes)) {
            itemList = inviteCodes.stream().filter(p -> p.getMakeName() != null).map(InviteCode::getMakeName).distinct().collect(Collectors.toList());
        }
        return itemList;
    }

    @Override
    public PageVo<InviteCode> selectByCondition(String useType, String makeName, Integer isDesc, int pageNum, int pageSize) {
        IPage<InviteCode> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<InviteCode> queryWrapper = new LambdaQueryWrapper<>();
        if (StringUtils.isBlank(useType) && StringUtils.isBlank(makeName)) {
            if (isDesc == 1) {
                //降序
                queryWrapper.orderByDesc(InviteCode::getCreateTime);
            } else {
                queryWrapper.orderByAsc(InviteCode::getCreateTime);
            }
            IPage<InviteCode> iPage = inviteCodeMapper.selectPage(page, queryWrapper);
            return new PageVo<InviteCode>(iPage);
        }
        if (!StringUtils.isEmpty(useType)) {
            queryWrapper.eq(InviteCode::getUseType, useType);
        }
        if (!StringUtils.isEmpty(makeName)) {
            queryWrapper.eq(InviteCode::getMakeName, makeName);
        }
        if (isDesc == 1) {
            //降序
            queryWrapper.orderByDesc(InviteCode::getCreateTime);
        } else {
            queryWrapper.orderByAsc(InviteCode::getCreateTime);
        }
        IPage<InviteCode> iPage = inviteCodeMapper.selectPage(page, queryWrapper);
        return new PageVo<InviteCode>(iPage);
    }

    @Override
    public InviteCode getInviteCodeByCode(String code) {
        LambdaQueryWrapper<InviteCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InviteCode::getCode, code.toUpperCase());
        return inviteCodeMapper.selectOne(wrapper);
    }

    @Override
    public List<InviteCode> getInviteCodeByMakeTime(Long labId, Date makeTime) {
        LambdaQueryWrapper<InviteCode> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(InviteCode::getLabId, labId);
        wrapper.ge(InviteCode::getCreateTime, makeTime);
        return inviteCodeMapper.selectList(wrapper);
    }
}
